#pragma once

#include "funpl.h"

namespace funpl
{

namespace ast
{
	// Prototypes
	struct node;
	
	struct module;
	struct namespace_;

	struct function;
	struct struct_;
	struct class_;
	struct typegroup;
	struct typedef_;

	struct type;
	struct metaarguments;

	struct metatype;
	struct metavariable;

	struct char_literal;
	struct string_literal;
	struct num_literal;

	struct statement;
	struct variable;
	struct compound;
	struct if_statement;
	struct try_statement;
	struct new_expression;
	struct delete_expression;
	struct guard_expression;
	struct unguard_expression;

	struct arguments;
	struct evaluate;
	struct expression;
	struct type_expression;

} // namespace

namespace parser
{

struct parser_state;

/// Parses a module.
ast::module* parse_module(parser_state &state, ast::node *parent);

/// Parses the declarations in a namespace.
void maybe_parse_namespace_body(parser_state &state, ast::namespace_ *namespace_);

/// Parses a function.
ast::function* parse_function(parser_state &state, ast::node *parent, bool anonymous, bool implicitSemicolon);
/// Parses a function.
ast::function* parse_global_function(parser_state &state, ast::node *parent);
/// Parses a structure.
ast::struct_* parse_struct(parser_state &state, ast::node *parent);
/// Parses a class.
ast::class_* parse_class(parser_state &state, ast::node *parent);
/// Parses a typegroup.
ast::typegroup* parse_typegroup(parser_state &state, ast::node *parent);
/// Parses a typedef.
ast::typedef_* parse_typedef(parser_state &state, ast::node *parent, bool implicitSemicolon);

/// Parses a type.
ast::type* parse_type(parser_state &state, ast::node *parent, bool implicitSemicolon);
/// Parses template arguments.
ast::metaarguments* parse_metaarguments(parser_state &state, ast::node *parent, bool implicitSemicolon);

/// Parses a metatype definition.
ast::metatype* parse_metatype(parser_state &state, ast::node *parent, bool implicitSemicolons);
/// Parses a metavariable definition.
ast::metavariable* parse_metavariable(parser_state &state, ast::node *parent, bool implicitSemicolons);

/// Parses a character literal.
ast::char_literal* parse_char_literal(parser_state &state, ast::node *parent);
/// Parses a string literal.
ast::string_literal* parse_string_literal(parser_state &state, ast::node *parent);
/// Parses a numeric literal.
ast::num_literal* parse_num_literal(parser_state &state, ast::node *parent);

/// Parses a variable.
ast::variable* parse_variable(parser_state &state, ast::node *parent, bool implicitSemicolon);
/// Parses a compound.
ast::compound* parse_compound(parser_state &state, ast::node *parent);
/// Parses an if statement.
ast::if_statement* parse_if_statement(parser_state &state, ast::node *parent, bool implicitSemicolon);
/// Parses a try-catch statement.
ast::try_statement* parse_try_statement(parser_state &state, ast::node *parent, bool implicitSemicolon);
/// Parses a new expression.
ast::new_expression* parse_new_expression(parser_state &state, ast::node *parent);
/// Parses a delete expression.
ast::delete_expression* parse_delete_expression(parser_state &state, ast::node *parent, bool implicitSemicolon);
/// Parses a guard expression.
ast::guard_expression* parse_guard_expression(parser_state &state, ast::node *parent, bool implicitSemicolon);
/// Parses an unguard expression.
ast::unguard_expression* parse_unguard_expression(parser_state &state, ast::node *parent);
/// Parses a statement.
ast::statement* parse_statement(parser_state &state, ast::node *parent);

/// Parses a list of function arguments.
ast::arguments* parse_function_arguments(parser_state &state, ast::node *parent);
/// Parses a list of function arguments passed to the given expression.
ast::evaluate* parse_function_evaluation(parser_state &state, ast::node *parent, ast::expression *expression);
/// Parses an expression.
ast::expression* parse_expression(parser_state &state, ast::node *parent, bool implicitSemicolon);
/// Parses a type expression.
ast::type_expression* parse_type_expression(parser_state &state, ast::node *parent, bool implicitSemicolon);

} // namespace

} // namespace